/*
 * @Descripttion: 
 * @version: 
 * @Author: xuyang
 * @Date: 2021-05-17 21:30:11
 * @LastEditors: xuyang
 * @LastEditTime: 2021-05-18 00:49:50
 */
import {
  Controller,
  Get,
  Provide,
  Inject,
  Query,
  Post,
  Body,
  ALL,
  App,
  Session
} from "@midwayjs/decorator";
import { Application, Context } from 'egg';
import { CreateApiDoc } from '@midwayjs/swagger'
import { UserService } from '../service/user';
import { IResponse, loginParams, IDeleteUser } from "../interface";
import { decrypt } from "../util/rsa";
import { getMd5 } from "../util";
import * as jwt from 'jsonwebtoken';

//node.js 文件操作对象
const fs = require('fs');
//node.js 路径操作对象
const path = require('path');
//管道读入一个虫洞。
const sendToWormhole = require('stream-wormhole');

const svgCaptcha = require('svg-captcha');
@Provide()
// 部分使用
@Controller('/user')
export class UserController {

  @Inject()
  userService: UserService;

  @Inject()
  ctx: Context;

  @App()
  app: Application

  @CreateApiDoc()
  .description('获取所有用户信息')
  .build()
  @Get('/getAllUsersByParams')
  async getAllUsersByParams() {
    try {
      const user = this.ctx.query;
      const data = await this.userService.getAllUsersByParams(user);
      return {
        code: 0,
        message: '查询成功',
        data: data
      };
    } catch (error) {
      return {
        code: -1,
        message: error.message,
        data: {}
      };
    }
  }

  @CreateApiDoc()
  .description('获取用户详情')
  .param('用户id', {
    required: true,
    example: "7de4185c-ae31-42fb-a394-974264e9aede",
    description: '用户id'
  })
  .build()
  @Get('/getUserDetail')
  async getUserByInfo(@Query() id: string) {
    const data = await this.userService.getUserDetail(id);
    return {
      code: 0,
      message: '查询成功',
      data: data
    };
  }

  @CreateApiDoc()
  .description('更新用户信息')
  .build()
  @Post('/edit')
  async updateUser(@Body(ALL) params: object) {
    const data = await this.userService.updateUser(params);
    return {
      code: 0,
      message: '更新成功',
      data: data
    };
  }

  @CreateApiDoc()
  .description('删除用户')
  .build()
  @Post('/del')
  async deleteUser(@Body(ALL) params: IDeleteUser) {
    const delParams = {
      id: params.id,
      status: 2
    }
    if(params.id + ''=== '1'){
      return {
        code: -1,
        message: '超级管理员禁止删除',
        data: []
      }
    } else {
      const data = await this.userService.updateUser(delParams);
      return {
        code: 0,
        message: '删除成功',
        data: data
      };
    }
  }
  /**
   * 启用/ 停用 用户
   * @param params 
   */
  @Post('/enable')
  async enable(@Body(ALL) params:  any){
    const enableParams = {
      id: params.id,
      status: params.type
    }
    if(params.id + ''=== '1'){
      return {
        code: -1,
        message: '超级管理员禁止停用',
        data: []
      }
    } else {
      const data = await this.userService.updateUser(enableParams);
      return {
        code: 0,
        message: '修改成功',
        data: data
      };
    }
  }


  @CreateApiDoc()
  .description('新增用户')
  .build()
  @Post('/add')
  async add(@Body(ALL) params: any) {
    const user = await this.userService.findOneUser(params.username);
    if(user){
      return {
        code: -1,
        message: '用户名已存在',
        data: []  
      }
    }
    const data = await this.userService.addNewUser(params);
    return {
      code: 0,
      message: '新增成功',
      data: data
    };
  }

  /**
   * 登录
   * @param params
   * @returns
   */
  @CreateApiDoc()
  .description('用户登录')
  .build()
  @Post('/login')
  async login(@Body(ALL) params: loginParams, @Session(ALL) session):Promise<IResponse>  {
    // 根据用户名,查询用户
    const data = await this.userService.findOneUser(params.username);
    if (data) {
      // 当前用户存在.
      try{
        const loginCode = session.loginCode;
        if(loginCode.toLowerCase() !== params.code.toLowerCase()){
          return {
            code: -1,
            message:'验证码错误',
            data: []
          }
        }
        // 解密
        let password = decrypt(params.password); // 密码解密
        // md5加密
        let md5Password = getMd5(password);
        if(md5Password !== data.password){
          return {
            code: -1,
            message: '密码错误',
            data: []
          }
        }else {
          let token = jwt.sign({ name: data.username }, this.app.config.jwt.secret, { expiresIn: this.app.config.jwt.expiresIn } )
          delete data.password
          return {
            code: 0,
            message: '登录成功',
            data: {
              ...data,
              token
            }
          }
        }
      }catch(e: any){
        return {
          code: -1,
          message: '密码错误',
          data: []
        }
      }
    }
    return {
      code: -1,
      message: '账号错误,请核对',
      data: []
    }
  }

  @Get('/code')
  async getCode(@Session(ALL) session): Promise<any> { 
    const options = {// 参数
      width: 80,
      height: 32, // height of captcha
      fontSize: 42, // captcha text size
      color: true,
      noise: 2,
    }
    var captcha = svgCaptcha.create(options);

    session.loginCode = captcha.text;
    this.ctx.response.type = 'svg';
    return captcha.data;
  }
  /**
   * 上传头像
   */
  @Post('/headImg')
  async uploadImg(){
    const stream = await this.ctx.getFileStream();
     //新建一个文件名
    let filename = new Date().getTime() + stream.filename;  // stream对象也包含了文件名，大小等基本信息
     //文件生成绝对路径
    //当然这里这样市不行的，因为你还要判断一下是否存在文件路径
    const targetPath = path.join(this.app.config.baseDir, '/public/uploads', stream.fields.username);
    if(!fs.existsSync(targetPath)){
      // 如果文件夹不存在, 就创建
      fs.mkdirSync(targetPath)
    }
    const result = await new Promise<any>((resolve, reject) => {
      //生成一个文件写入 文件流
      const target = path.join(targetPath, filename)
      const remoteFileStream = fs.createWriteStream(target)
      // 以管道方式写入流
      stream.pipe(remoteFileStream)

      let errFlag 
      // 监听error事件
      remoteFileStream.on('error', err => {
        errFlag = true
        // 停止写入
        sendToWormhole(stream)
        remoteFileStream.destroy()
        console.log(err)
        reject({err: err})
      })
      
      // 监听写入完成事件
      remoteFileStream.on('finish', () => {
        if (errFlag) return
        resolve({ url: '/public/uploads'+ filename, filename})
      })
    })
    if(result.err){
      this.ctx.body = {
        code: -1,
        message: result.err.message
      }
    }else {
      this.ctx.body = {
        path: path.join('/public/uploads/' , stream.fields.username),
        url: path.join('/public/uploads/' , stream.fields.username, filename),
      }
    }
  }
  @CreateApiDoc()
  .description('修改密码')
  .build()
  @Post('/changePsw')
  async changePsw(@Body(ALL) params: any) {
    // 解密
    let oldPwd = decrypt(params.oldPwd); // 密码解密
    // md5加密
    let md5OldPassword = getMd5(oldPwd);

    const newPwd = decrypt(params.newPwd);
    const md5NewPassword = getMd5(newPwd);

    const updatePwdParams = {
      username: params.username,
      oldPwd: md5OldPassword,
      newPwd: md5NewPassword
    }

    const data = await this.userService.updatePwd(updatePwdParams);
    if (data) {
      return {
        code: 0,
        message: '修改成功'
      }
    }
    return {
      code: 1,
      message: '账号或旧密码有误，请核对后输入'
    }
  }
}
